﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace ElveTouch
{
    public class WatermarkTextBox : TextBox
    {
        private Font _oldFont = null;
        private Boolean _waterMarkTextEnabled = false;
        private const int WM_PAINT = 0x000F;

        #region Attributes
        private Color _waterMarkColor = Color.DarkGray;
        [Category("Appearance"), DefaultValue(typeof(Color), "DarkGray")]
        public Color WaterMarkColor
        {
            get { return _waterMarkColor; }
            set
            {
                _waterMarkColor = value;
                Invalidate();
            }
        }

        private string _waterMarkText = string.Empty;
        [Category("Appearance"), DefaultValue("")]
        public string WaterMarkText
        {
            get { return _waterMarkText; }
            set
            {
                _waterMarkText = value; 
                Invalidate();
            }
        }
        #endregion

        /// 
        /// Default constructor
        /// 
        public WatermarkTextBox()
        {
            joinEvents(true);
        }

        /// 
        /// Override OnCreateControl ... thanks to  "lpgray .. codeproject guy"
        /// 
        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            toggleWatermark(null, null);
        }

        private void drawWatermark()
        {
            Graphics g = Graphics.FromHwnd(this.Handle);
            if (_waterMarkTextEnabled)
            {
                Color tempBackColor = BackColor;
                Color tempForeColor = WaterMarkColor;
                if (this.Enabled == false)
                {
                    if (this.BackColor == SystemColors.Window) // Windows seems to only show a grayed out back color when disabled when the normal backcolor is set to SystemColors.Window
                        tempBackColor = SystemColors.Control;
                    tempForeColor = SystemColors.ControlLight;
                }

                TextFormatFlags formatFlags = this.Multiline ? TextFormatFlags.Top : TextFormatFlags.VerticalCenter;

                // Use the same font that was defined in base class
                using (System.Drawing.Font drawFont = new System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit))
                {
                    TextRenderer.DrawText(g, WaterMarkText, drawFont, this.ClientRectangle, tempForeColor, tempBackColor, formatFlags);
                }
            }
        }

        private void joinEvents(Boolean join)
        {
            if (join)
            {
                this.TextChanged += new System.EventHandler(this.toggleWatermark);
                this.LostFocus += new System.EventHandler(this.toggleWatermark);
                this.FontChanged += new System.EventHandler(this.onFontChanged);
                this.GotFocus += new System.EventHandler(this.toggleWatermark);
            }
        }

        private void toggleWatermark(object sender, EventArgs args)
        {
            if (this.Text.Length <= 0 && !this.Focused)
                enableWatermark();
            else
                disableWatermark();
        }

        private void enableWatermark()
        {
            //Save current font until returning the UserPaint style to false (NOTE: It is a try and error advice)
            _oldFont = new System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit);
            //Enable OnPaint event handler
            this._waterMarkTextEnabled = true;
            //Triger OnPaint immediatly
            Invalidate();
        }

        private void disableWatermark()
        {
            //Disbale OnPaint event handler
            this._waterMarkTextEnabled = false;
            //Return back _oldFont if existed
            if (_oldFont != null)
                this.Font = new System.Drawing.Font(_oldFont.FontFamily, _oldFont.Size, _oldFont.Style, _oldFont.Unit);
            Invalidate();
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_PAINT:
                    base.WndProc(ref m);
                    drawWatermark();
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        private void onFontChanged(object sender, EventArgs args)
        {
            if (_waterMarkTextEnabled)
            {
                _oldFont = new System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit);
                Refresh();
            }
        }
    }
}